// OpentTxl-C Version 11 limits
// J.R. Cordy, Jan 2023

// Copyright 2023, James R. Cordy and others

// Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
// and associated documentation files (the “Software”), to deal in the Software without restriction, 
// including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all copies 
// or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
// AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// TXL processor limits
// Maximum limits on sizes of parsing / transformation data structures and processing steps

// Modification Log

// v11.0 Initial revision, adapted from OpenTxl 11.0

// I/O, strings, memory allocation
#include "support.h"

// Check interface consistency
#include "limits.h"

// Global modules
#include "locale.h"
#include "options.h"
#include "tokens.h"
#include "trees.h"
#include "errors.h"

// Maximum total defined symbols in a TXL program
int maxSymbols; // = 16384 + (options.txlSize div 200) * 2048 = 16384, 18432 (200), 20480 (400) .. 26624 (1000)

// Maximum number of rules in a TXL program
int maxRules; // = 4096 + (options.txlSize div 200) * 1024 = 4096, 5120 (200), 6144 (400) .. 9216 (1000)

// Maximum different token texts, including identifiers, strings and numbers,
// in entire TXL program - must be a power of 2!
int maxIdents;  // = vmaxIdents

// Maximum total characters in token texts
int maxIdentChars; // maxIdents * 32    // (statistical estimate of ratio)

// Maximum total length of any input,
// including each of: TXL bootstrap grammar, TXL program, input source
int maxTokens; // options.transformSize * 4000 

// Maximum number of lines in any single input,
// including each of: TXL bootstrap grammar, TXL program, input source
int maxLines; // = maxTokens div 10

// Maximum parsing depth in any parse
// Normally should allow for the length of the whole input file
int maxParseDepth; // = maxLines

// Maximum parsing cycles in any parse
// Normally should allow for the length of the whole input file
int maxParseCycles; // = min (1000000 + 100 * maxTokens, 500000000)

// Maximum rule call depth
// Normally should allow for at least the length of the whole input file
// so that a recursive function can examine every line
int maxCallDepth; // = maxParseDepth div 4

// Limits on total number of trees and kids in all trees
int maxTrees; // = options.transformSize * 50000
int maxKids;  // = (maxTrees * 3) div 2

// Limit on TXL recursion stack use 
addressint maxStackUse; // = defaultStackUse

// Initializer
void limits (void) {
    // Maximum total defined symbols in a TXL program
    maxSymbols = 16384 + ((options_txlSize / 200) * 2048);

    // Maximum number of rules in a TXL program
    maxRules = 4096 + ((options_txlSize / 200) * 1024);

    // Maximum different token texts, including identifiers, strings and numbers,
    // in entire TXL program - must be a power of 2!
    // Note - if maxIdents ever exceeds 65536, we must change the width of tree nodes!
    int vmaxIdents = 2048; // = 2048, 4096, 8192, ...
    for(;;) {
        if ((vmaxIdents >= (options_txlSize * 1024)) || (vmaxIdents == 1048576)) {
            break;
        };
        vmaxIdents *= 2;
    };
    maxIdents = vmaxIdents;

    // Maximum total characters in token texts
    maxIdentChars = maxIdents * 32;

    // Maximum total length of any input,
    // including each of: TXL bootstrap grammar, TXL program, input source
    maxTokens = options_transformSize * 4000;

    // Maximum number of lines in any single input,
    // including each of: TXL bootstrap grammar, TXL program, input source
    maxLines = maxTokens / 10;

    // Maximum parsing depth in any parse
    // Normally should allow for the length of the whole input file
    maxParseDepth = maxLines;

    // Maximum parsing cycles in any parse
    // Normally should allow for the length of the whole input file
    maxParseCycles =  min (1000000 + (100 * maxTokens), 500000000);

    // Maximum rule call depth
    // Normally should allow for at least the length of the whole input file
    // so that a recursive function can examine every line
    maxCallDepth = maxParseDepth / 4;

    // Limits on total number of trees and kids in all trees
    maxTrees = options_transformSize * 50000;
    maxKids = (maxTrees * 3) / 2;

    // Limit on TXL recursion stack use 
    addressint defaultStackUse = (addressint) (maxParseDepth * 128);

    // Can't use min() for this when machine might be 64 bit
    if ( defaultStackUse > ((256 * 1024) * 1024)) {     // 256 Mb is most we are willing to use
        defaultStackUse = (addressint) 268435456;
    };

    // We need at least these to run
    #define reservedStack 1048576               // 1 mb
    #define minimumStack  4194304               // 4 mb

    // Do we have less than we'd like at this size?
    if ((stackSize - reservedStack) < defaultStackUse) {
        // Yes, let's see how bad it is
        addressint oldStackUse = defaultStackUse;
        defaultStackUse = stackSize - reservedStack;
        if (defaultStackUse >= minimumStack) {
            if (((options_option[verbose_p]) && (!(options_option[compile_p]))) && 
                    ((defaultStackUse < (oldStackUse / 2)) || (options_option[verbose_p]))) {
                error("", "Stack limit less than recommended for TXL size (probable cause: shell stack limit)", 
                    WARNING, 911);
                string message;
                stringprintf (message, "Recursion stack limit reduced from %llu to %llu to fit", oldStackUse, defaultStackUse);
                error("", message, INFORMATION, 913);
            }
        } else {
            error("", "Stack limit less than minimum for TXL size (probable cause: shell stack limit)", FATAL, 912);
        };
    };
    maxStackUse = (addressint) defaultStackUse;
}
